﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;

namespace AV_Monitor
{
    public partial class MainForm : Form
    {
        private JoystickHandler joy = new JoystickHandler();

        public enum MessageType { Incoming, Outgoing, Normal, Warning, Error };

        NmeaParserDllInterface nmeaPI = new NmeaParserDllInterface();
        private Color[] MessageColor = { Color.Blue, Color.Green, Color.Black, Color.Orange, Color.Red };
        private Color[] AVX03MessageColor = { Color.Black, Color.Red };
        private SerialPort comPort = new SerialPort();

        private TextWriter tw = null;

        System.Timers.Timer aTimer = new System.Timers.Timer();

        public MainForm()
        {
            InitializeComponent();

            comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);

            joy.Init(this.Handle);
         }

        private void MainForm_Load(object sender, EventArgs e)
        {
            // Set Parity Values
            foreach (string str in Enum.GetNames(typeof(Parity)))
                comboBoxParity.Items.Add(str);
            comboBoxParity.SelectedIndex = 0;
            //Set Stop Bit Values(object obj)
            foreach (string str in Enum.GetNames(typeof(StopBits)))
                comboBoxStopBits.Items.Add(str);
            comboBoxStopBits.SelectedIndex = 1;
            // Set Port Name Values        {
            foreach (string str in SerialPort.GetPortNames())
                comboBoxPort.Items.Add(str);
            comboBoxPort.SelectedIndex = 0;

            comboBoxBaudRate.SelectedText = "57600";
            comboBoxDataBits.SelectedIndex = 1;
        }

        #region Log file I/O
        public bool OpenFile()
        {
            try
            {
                // Close file if is already open
                if (IsFileOpened())
                    CloseFile();
                
                string fileName = DateTime.Now.ToString("dd_MM_yyyy__hh_mm_ss") + ".log";
                tw = new StreamWriter(fileName);

                tw.WriteLine("Yaw, Pitch , Roll, Reserve1, Reserve2, Reserve3, Reserve4");
                
                DisplayAVX03Data(Color.Black, "File " + fileName + " opened.\n");
                return true;
            }
            catch (Exception ex)
            {
                DisplayAVX03Data(Color.Red, ex.Message);
                return false;
            }
        }

        public void CloseFile()
        {
            if (IsFileOpened())
            {
                tw.Close();
                tw.Dispose();
                tw = null;
            }
        }

        public bool IsFileOpened()
        {
            return tw != null;
        }

        #endregion
        
        #region ComPort I/O
        public bool OpenPort()
        {
            try
            {
                // Close port if is already open
                if (comPort.IsOpen == true)
                    ClosePort();

                // Set the properties of our SerialPort Object
                comPort.PortName = comboBoxPort.Text;
                comPort.BaudRate = int.Parse(comboBoxBaudRate.Text);
                comPort.Parity = (Parity)Enum.Parse(typeof(Parity), comboBoxParity.Text);
                comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBoxStopBits.Text);
                comPort.DataBits = int.Parse(comboBoxDataBits.Text);
                comPort.Open();

                DisplayData(MessageType.Normal, "Port opened at " + comboBoxPort.Text + " at " + DateTime.Now + "\n");

                return true;
            }
            catch (Exception ex)
            {
                DisplayData(MessageType.Error, ex.Message);
                return false;
            }
        }

        public bool ClosePort()
        {
            try
            {
                // Close port if is open
                if (comPort.IsOpen)
                {
                    comPort.Close();
                    DisplayData(MessageType.Normal, "Port at " + comboBoxPort.Text + " closed at " + DateTime.Now + "\n");
                }

                StopRecievingData();

                return true;
            }
            catch (Exception ex)
            {
                DisplayData(MessageType.Error, ex.Message);
                return false;
            }
        }

        public void WriteData(string str)
        {
            if (!comPort.IsOpen)
                comPort.Open();

            comPort.Write(str);

            DisplayData(MessageType.Outgoing, str);
        }

        public string ReadData()
        {
            string str = comPort.ReadExisting();
            
            DisplayData(MessageType.Incoming, str);

            return str;
        }
        #endregion //ComPort I/O

        #region Other
        /// <summary>
        /// Method that will be called when theres data waiting in the serial port buffer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string str = ReadData();

            NmeaParserDllInterface.ParseDll(str);

            string parsedData = NmeaParserDllInterface.GetYawDll().ToString() + " , ";
            parsedData += NmeaParserDllInterface.GetPitchDll().ToString() + " , ";
            parsedData += NmeaParserDllInterface.GetRollDll().ToString() + " , ";
            parsedData += NmeaParserDllInterface.GetReserve1Dll().ToString() + " , ";
            parsedData += NmeaParserDllInterface.GetReserve2Dll().ToString() + " , ";
            parsedData += NmeaParserDllInterface.GetReserve3Dll().ToString() + " , ";
            parsedData += NmeaParserDllInterface.GetReserve4Dll().ToString();

            if (IsFileOpened())
            {
                tw.WriteLine(parsedData);
                DisplayAVX03Data(Color.Red, parsedData + "\n");
            }
            else
            {
                DisplayAVX03Data(Color.Black, parsedData + "\n");
            }

        }

        private void SendMe(object source, ElapsedEventArgs e)
        {
            JoyState s = joy.Poll();

            if (s == null)  // No joystick
                return;

            NmeaParserDllInterface.SetJoystickXDll((float)s.AxisX);
            NmeaParserDllInterface.SetJoystickYDll((float)s.AxisY);
            NmeaParserDllInterface.SetJoystickZDll((float)s.AxisZ);
            NmeaParserDllInterface.SetThrottleDll((float)s.Throttle);
            String test = NmeaParserDllInterface.GeneratePCX03Dll();
            WriteData(test);
        }

        [STAThread]
        private void DisplayAVX03Data(Color messageColor, string msg)
        {
            richTextBoxAVX03.Invoke(new EventHandler(delegate
            {
                richTextBoxAVX03.SelectedText = string.Empty;
                richTextBoxAVX03.SelectionFont = new Font(richTextBoxAVX03.SelectionFont, FontStyle.Bold);
                richTextBoxAVX03.SelectionColor = messageColor;
                richTextBoxAVX03.AppendText(msg);
                richTextBoxAVX03.ScrollToCaret();
            }));
        }
        /// <summary>
        /// Method to display the data to & from the port on the screen
        /// </summary>
        /// <param name="type">MessageType of the message</param>
        /// <param name="msg">Message to display</param>
        [STAThread]
        private void DisplayData(MessageType type, string msg)
        {
            richTextBoxDisplay.Invoke(new EventHandler(delegate
            {
                richTextBoxDisplay.SelectedText = string.Empty;
                richTextBoxDisplay.SelectionFont = new Font(richTextBoxDisplay.SelectionFont, FontStyle.Bold);
                richTextBoxDisplay.SelectionColor = MessageColor[(int)type];
                richTextBoxDisplay.AppendText(msg);
                richTextBoxDisplay.ScrollToCaret();
            }));
        }
        #endregion

        #region Buttons
        private void buttonOpenClose_Click(object sender, EventArgs e)
        {
            if (buttonOpenClose.Text == "Open Port")
            {
                OpenPort();
                buttonOpenClose.Text = "Close Port";

                buttonSendingData.Enabled = true;
                buttonRecordingData.Enabled = true;
                comboBoxPort.Enabled = false;
                comboBoxBaudRate.Enabled = false;
                comboBoxParity.Enabled = false;
                comboBoxDataBits.Enabled = false;
                comboBoxStopBits.Enabled = false;
            }
            else
            {
                ClosePort();
                buttonOpenClose.Text = "Open Port";
                
                buttonSendingData.Enabled = false;
                buttonRecordingData.Enabled = false;
                comboBoxPort.Enabled = true;
                comboBoxBaudRate.Enabled = true;
                comboBoxParity.Enabled = true;
                comboBoxDataBits.Enabled = true;
                comboBoxStopBits.Enabled = true;
            }
        }           

        private void buttonStartStopRecieveingData_Click(object sender, EventArgs e)
        {
            if (buttonSendingData.Text == "Start Sending Data")
            {
                StartRecievingData();
            }
            else
            {
                StopRecievingData();
            } 
        }

        private void StartRecievingData()
        {
            buttonSendingData.Text = "Stop Sending Data";
                
            aTimer = new System.Timers.Timer();
            aTimer.Elapsed += new ElapsedEventHandler(SendMe);
            aTimer.Interval = Convert.ToDouble(1000 * 1 / numericUpDownFrequency.Value);
            aTimer.Enabled = true;
        }

        private void StopRecievingData()
        {
            buttonSendingData.Text = "Start Sending Data";
            if (aTimer!= null)
                aTimer.Enabled = false;
            aTimer = null;
        }

        private void buttonRecordingData_Click(object sender, EventArgs e)
        {
            if (buttonRecordingData.Text == "Start Recording Data")
            {
                StartRecordingData();
            }
            else
            {
                StopRecordingData();
            } 
        }

        private void StartRecordingData()
        {
            buttonRecordingData.Text = "Stop Recording Data";
            OpenFile();
        }

        private void StopRecordingData()
        {
            buttonRecordingData.Text = "Start Recording Data";
            CloseFile();
        }
        
        #endregion //Buttons

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.Space)
            {
                Abort();
                return;
            }
        }

        private void timerJoystick_Tick(object sender, EventArgs e)
        {
            JoyState s = joy.Poll();

            if (s == null)  // No joystick
                return;

            progressLeft.Value = 0;
            progressRight.Value = 0;
            if (s.AxisX < 0)
                progressLeft.Value = (int)(s.AxisX * -100);
            else if (s.AxisX > 0)
                progressRight.Value = (int)(s.AxisX * 100);

            verticalProgressDown.Value = 0;
            verticalProgressUp.Value = 0;
            if (s.AxisY < 0)
                verticalProgressDown.Value = (int)(s.AxisY * -100);
            else if (s.AxisY > 0)
                verticalProgressUp.Value = (int)(s.AxisY * 100);

            verticalProgressThrottle.Value = (int)(s.Throttle * 100);
            
            progressRudderLeft.Value = 0;
            progressRudderRight.Value = 0;
            if (s.AxisZ < 0)
                progressRudderLeft.Value = (int)(s.AxisZ * -100);
            else if (s.AxisZ > 0)
                progressRudderRight.Value = (int)(s.AxisZ * 100);    
        }

        void Abort()
        {
            timerJoystick.Enabled = false;
        
        }

    }
}
